package com.liqi.common.utils.uuid.idgenerate;


import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;


/**
 * 默认的ID生成器, 采用前缀+时间+原子数的形式实现
 * 建议相同的配置采用同一个实例
 * @see IdGeneratorConfig
 * @date:2021-08-09
 */
public class DefaultIdGenerator implements IdGenerator, Runnable{

	private String time;

	private AtomicInteger value;
	//yyyyMMddHHmmss
	private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

	private IdGeneratorConfig config;

	private Thread thread;

	private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

	public DefaultIdGenerator(){
		config = new DefaultIdGeneratorConfig();
		time = LocalDateTime.now().format(FORMATTER);
		value = new AtomicInteger(config.getInitial());

		thread = new Thread(this);
		thread.setDaemon(true);
		thread.start();
	}

	public DefaultIdGenerator(IdGeneratorConfig config){
		this.config = config;
		time = LocalDateTime.now().format(FORMATTER);
		value = new AtomicInteger(config.getInitial());

		thread = new Thread(this);
		thread.setDaemon(true);
		thread.start();
	}

	@Override
	public String next() {
		lock.readLock().lock();
		//默认补0　四位
		int num = value.getAndIncrement();
		
		//到达指定数值后重置，底层如果不同的秒数，那么从1开始。
		if(num==9999) {
			value = new AtomicInteger(config.getInitial());
		}
		
		//补零
		String numStr = String.format("%04d", num);

		StringBuffer sb = new StringBuffer(config.getPrefix())
				.append(config.getSplitString())
				.append(time)
				.append(config.getSplitString())
				.append(numStr);
		lock.readLock().unlock();
		return sb.toString();
	}

	@Override
	public void run() {
		while (true){
			try {
				Thread.sleep(1000 * config.getRollingInterval());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			String now = LocalDateTime.now().format(FORMATTER);
			if (!now.equals(time)){
				lock.writeLock().lock();
				time = now;
				value.set(config.getInitial());
				lock.writeLock().unlock();
			}
		}
	}

}
